/*
 * Copyright Miroslav Pokorny
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package lovely.gwt.jsonrpc.client;

import java.util.Map;
import java.util.List;
import java.util.ArrayList;

import rocket.util.client.Checker;

import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNull;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;

/**
 * Convenient base class invoker for any json rpc poster.
 * 
 * The generator will implement the {@link #readObject(JSONValue)} and
 * {@link #createSerializer()}.
 * 
 * @author Miroslav Pokorny
 */
abstract public class Request11ServiceInvoker<R> extends JsonServiceMethodInvoker<R> {

	/**
	 * Accumulates any parameters that accompany the request.
	 */
	private JSONObject parameters = new JSONObject();

	/**
	 * Accumulates any name of parameters that accompany the request.
	 */
	private List<String> parameterNames = new ArrayList<String>();

	protected JSONValue getParameters() {
		Checker.notNull("parameter:parameters", parameters);
		if (this.getRequestParameterType() == "object") {
			return this.parameters;
		} else {
			final JSONArray jsonArray = new JSONArray();
			int j = 0;
			for (String key : this.parameterNames) {
				jsonArray.set(j, this.parameters.get(key));
				j++;
			}
			return jsonArray;
		}
	}

	protected void setParameter(final JSONObject json, final String name,
			final JSONValue jsonValue) {
		json.put(name, jsonValue);
	}
	protected void addParameter(final String name, final JSONValue jsonValue) {
		this.parameters.put(name, jsonValue);
		this.parameterNames.add(name);
	}

	/**
	 * Adds a new boolean value parameter to the parameters that will be sent
	 * when the request is made.
	 * 
	 * @param name
	 * @param booleanValue
	 */
	public void addParameter(final String name, final boolean booleanValue) {
		this.addParameter(name, JSONBoolean.getInstance(booleanValue));
	}

	public void addParameter(final String name, final byte byteValue) {
		this.addParameter(name, new JSONNumber(byteValue));
	}

	public void addParameter(final String name, final short shortValue) {
		this.addParameter(name, new JSONNumber(shortValue));
	}

	public void addParameter(final String name, final int intValue) {
		this.addParameter(name, new JSONNumber(intValue));
	}

	public void addParameter(final String name, final long longValue) {
		this.addParameter(name, new JSONNumber(longValue));
	}

	public void addParameter(final String name, final float floatValue) {
		this.addParameter(name, new JSONNumber(floatValue));
	}

	public void addParameter(final String name, final double doubleValue) {
		this.addParameter(name, new JSONNumber(doubleValue));
	}

	public void addParameter(final String name, final char charValue) {
		this.addParameter(name, new JSONString(Character.toString(charValue)));
	}

	public void addParameter(final String name, final String value) {
		Checker.notEmpty("parameter:name", name);
		if (value == null) {
			addParameter(name, JSONNull.getInstance());
			return;
		}
		addParameter(name, new JSONString(value));
	}

	public JSONArray createJSONArray(String[] values) {
		final JSONArray jsonArray = new JSONArray();
		int i = 0;
		for (String value : values) {
			jsonArray.set(i, new JSONString(value));
			i++;
		}
		return jsonArray;
	}

	public void addParameter(final String name, final String[] values) {
		Checker.notEmpty("parameter:name", name);
		if (values == null) {
			addParameter(name, JSONNull.getInstance());
			return;
		}
		addParameter(name, createJSONArray(values));
	}

	public void addParameter(final String name, final String[][] values) {
		Checker.notEmpty("parameter:name", name);
		if (values == null) {
			addParameter(name, JSONNull.getInstance());
			return;
		}
		final JSONArray jsonMultiArray = new JSONArray();
		int j = 0;
		for (String row[] : values) {
			jsonMultiArray.set(j, createJSONArray(row));
			j++;
		}
		addParameter(name, jsonMultiArray);
	}

	public void addParameter(final String name, final String[][][] values) {
		Checker.notEmpty("parameter:name", name);
		if (values == null) {
			addParameter(name, JSONNull.getInstance());
			return;
		}
		final JSONArray jsonMultiArray = new JSONArray();
		int j = 0;
		for (String[] row[] : values) {
			final JSONArray jsonArray = new JSONArray();
			int i = 0;
			for (String row2[] : row) {
				jsonArray.set(i, createJSONArray(row2));
				i++;
			}
			jsonMultiArray.set(j, jsonArray);
			j++;
		}
		addParameter(name, jsonMultiArray);
	}

	public void addParameter(final String name, final Map<String, String> map) {
		if (map == null) {
			addParameter(name, JSONNull.getInstance());
			return;
		}
		final JSONObject jsonMap = new JSONObject();
		for (Map.Entry<String, String> entry: map.entrySet()) {
			jsonMap.put(entry.getKey(), new JSONString(entry.getValue()));
		}
		addParameter(name, jsonMap);
	}

}
